#include "sdram.h"
#include "stm32f429xx.h"
#include "delay.h"

/**
 * @brief       向SDRAM发送命令
 * @param       bankx       : 0,向BANK5上面的SDRAM发送指令
 * @param                     1,向BANK6上面的SDRAM发送指令
 * @param       cmd         : 指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电)
 * @param       refresh     : 自刷新次数(cmd=3时有效)
 * @param       regval      : 模式寄存器值
 * @retval      返回值       :0,正常; 1,失败.
 */
uint8_t sdram_send_cmd(uint8_t bankx, uint8_t cmd, uint8_t refresh, uint16_t regval)
{
    uint32_t retry = 0;
    uint32_t tempreg = 0;
    
    tempreg |= cmd << 0;            /* 设置指令 */
    tempreg |= 1 << (4 - bankx);    /* 设置发送指令到bank5还是6 */
    tempreg |= refresh << 5;        /* 设置自刷新次数 */
    tempreg |= regval << 9;         /* 设置模式寄存器的值 */
    FMC_Bank5_6->SDCMR = tempreg;   /* 配置寄存器 */

    while ((FMC_Bank5_6->SDSR & (1 << 5)))  /* 等待指令发送完成 */
    {
        retry++;

        if (retry > 0X1FFFFF)return 1;
    }

    return 0;
}

/**
 * @brief       初始化SDRAM
 * @param       无
 * @retval      无
 */
void sdram_init(void)
{
    uint32_t sdctrlreg = 0, sdtimereg = 0;
    uint16_t mregval = 0;
    
    /* 使能PC/PD/PE/PF/PG时钟 */
    RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOCEN|RCC_AHB1ENR_GPIODEN|RCC_AHB1ENR_GPIOEEN|RCC_AHB1ENR_GPIOFEN| 
                    RCC_AHB1ENR_GPIOGEN);
    RCC->AHB3ENR |= RCC_AHB3ENR_FMCEN; /* 使能FMC时钟 */

    /* PC0/2/3 复用功能输出 */
    GPIOC->MODER &= ~(GPIO_MODER_MODE0_Msk|GPIO_MODER_MODE2_Msk|GPIO_MODER_MODE3_Msk);
    GPIOC->MODER |= (GPIO_MODER_MODE0_1|GPIO_MODER_MODE2_1|GPIO_MODER_MODE3_1);
    GPIOC->OTYPER &= ~(GPIO_OTYPER_OT0_Msk|GPIO_OTYPER_OT2_Msk|GPIO_OTYPER_OT3_Msk);
    GPIOC->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0_Msk|GPIO_OSPEEDR_OSPEED2_Msk|GPIO_OSPEEDR_OSPEED3_Msk);
    GPIOC->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0_0|GPIO_OSPEEDER_OSPEEDR0_1|GPIO_OSPEEDER_OSPEEDR2_0|
                    GPIO_OSPEEDER_OSPEEDR2_1|GPIO_OSPEEDER_OSPEEDR3_0|GPIO_OSPEEDER_OSPEEDR3_1);
    GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk|GPIO_PUPDR_PUPD2_Msk|GPIO_PUPDR_PUPD3_Msk);
    GPIOC->PUPDR |= (GPIO_PUPDR_PUPD0_0|GPIO_PUPDR_PUPD2_0|GPIO_PUPDR_PUPD3_0);
    /* PD0/1/8/9/10/14/15 复用功能输出 */
    GPIOD->MODER &= ~(GPIO_MODER_MODE0_Msk|GPIO_MODER_MODE1_Msk|GPIO_MODER_MODE8_Msk|GPIO_MODER_MODE9_Msk|   
                    GPIO_MODER_MODE10_Msk|GPIO_MODER_MODE14_Msk|GPIO_MODER_MODE15_Msk);
    GPIOD->MODER |= (GPIO_MODER_MODE0_1|GPIO_MODER_MODE1_1|GPIO_MODER_MODE8_1|GPIO_MODER_MODE9_1|   
                    GPIO_MODER_MODE10_1|GPIO_MODER_MODE14_1|GPIO_MODER_MODE15_1);
    GPIOD->OTYPER &= ~(GPIO_OTYPER_OT0_Msk|GPIO_OTYPER_OT1_Msk|GPIO_OTYPER_OT8_Msk|GPIO_OTYPER_OT9_Msk|  
                    GPIO_OTYPER_OT10|GPIO_OTYPER_OT14|GPIO_OTYPER_OT15);
    GPIOD->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0_Msk|GPIO_OSPEEDR_OSPEED1_Msk|GPIO_OSPEEDR_OSPEED8_Msk|   
                    GPIO_OSPEEDR_OSPEED9_Msk|GPIO_OSPEEDR_OSPEED10_Msk|GPIO_OSPEEDR_OSPEED14_Msk|  
                    GPIO_OSPEEDR_OSPEED15_Msk);
    GPIOD->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0_0|GPIO_OSPEEDER_OSPEEDR0_1|GPIO_OSPEEDER_OSPEEDR1_0|
                    GPIO_OSPEEDER_OSPEEDR1_1|GPIO_OSPEEDER_OSPEEDR8_0|GPIO_OSPEEDER_OSPEEDR8_1|
                    GPIO_OSPEEDER_OSPEEDR9_0|GPIO_OSPEEDER_OSPEEDR9_1|GPIO_OSPEEDER_OSPEEDR10_0|
                    GPIO_OSPEEDER_OSPEEDR10_1|GPIO_OSPEEDER_OSPEEDR14_0|GPIO_OSPEEDER_OSPEEDR14_1|
                    GPIO_OSPEEDER_OSPEEDR15_0|GPIO_OSPEEDER_OSPEEDR15_1);
    GPIOD->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk|GPIO_PUPDR_PUPD1_Msk|GPIO_PUPDR_PUPD8_Msk|GPIO_PUPDR_PUPD9_Msk|  
                    GPIO_PUPDR_PUPD10_Msk|GPIO_PUPDR_PUPD14_Msk|GPIO_PUPDR_PUPD15_Msk);
    GPIOD->PUPDR |= (GPIO_PUPDR_PUPD0_0|GPIO_PUPDR_PUPD1_0|GPIO_PUPDR_PUPD8_0|GPIO_PUPDR_PUPD9_0|  
                    GPIO_PUPDR_PUPD10_0|GPIO_PUPDR_PUPD14_0|GPIO_PUPDR_PUPD15_0);
    /* PE0/1/7~15 复用功能输出 */
    GPIOE->MODER &= ~(GPIO_MODER_MODE0_Msk|GPIO_MODER_MODE1_Msk|GPIO_MODER_MODE7_Msk|GPIO_MODER_MODE8_Msk|  
                  GPIO_MODER_MODE9_Msk|GPIO_MODER_MODE10_Msk|GPIO_MODER_MODE11_Msk|GPIO_MODER_MODE12_Msk|  
                  GPIO_MODER_MODE13_Msk|GPIO_MODER_MODE14_Msk|GPIO_MODER_MODE15_Msk);
    GPIOE->MODER |= (GPIO_MODER_MODE0_1|GPIO_MODER_MODE1_1|GPIO_MODER_MODE7_1|GPIO_MODER_MODE8_1|  
                    GPIO_MODER_MODE9_1|GPIO_MODER_MODE10_1|GPIO_MODER_MODE11_1|GPIO_MODER_MODE12_1|  
                    GPIO_MODER_MODE13_1|GPIO_MODER_MODE14_1|GPIO_MODER_MODE15_1);
    GPIOE->OTYPER &= ~(GPIO_OTYPER_OT0_Msk|GPIO_OTYPER_OT1_Msk|GPIO_OTYPER_OT7_Msk|GPIO_OTYPER_OT8_Msk|  
                    GPIO_OTYPER_OT9_Msk|GPIO_OTYPER_OT10_Msk|GPIO_OTYPER_OT11_Msk|GPIO_OTYPER_OT12_Msk|  
                    GPIO_OTYPER_OT13_Msk|GPIO_OTYPER_OT14_Msk|GPIO_OTYPER_OT15_Msk);
    GPIOE->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0_Msk|GPIO_OSPEEDR_OSPEED1_Msk|GPIO_OSPEEDR_OSPEED7_Msk|  
                        GPIO_OSPEEDR_OSPEED8_Msk|GPIO_OSPEEDR_OSPEED9_Msk|GPIO_OSPEEDR_OSPEED10_Msk|  
                        GPIO_OSPEEDR_OSPEED11_Msk|GPIO_OSPEEDR_OSPEED12_Msk|GPIO_OSPEEDR_OSPEED13_Msk|  
                        GPIO_OSPEEDR_OSPEED14_Msk|GPIO_OSPEEDR_OSPEED15_Msk);
    GPIOE->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0_0|GPIO_OSPEEDER_OSPEEDR0_1|GPIO_OSPEEDER_OSPEEDR1_0|
                    GPIO_OSPEEDER_OSPEEDR1_1|GPIO_OSPEEDER_OSPEEDR7_0|GPIO_OSPEEDER_OSPEEDR7_1|
                    GPIO_OSPEEDER_OSPEEDR8_0|GPIO_OSPEEDER_OSPEEDR8_1|GPIO_OSPEEDER_OSPEEDR9_0|
                    GPIO_OSPEEDER_OSPEEDR9_1|GPIO_OSPEEDER_OSPEEDR10_0|GPIO_OSPEEDER_OSPEEDR10_1|
                    GPIO_OSPEEDER_OSPEEDR11_0|GPIO_OSPEEDER_OSPEEDR11_1|GPIO_OSPEEDER_OSPEEDR12_0|
                    GPIO_OSPEEDER_OSPEEDR12_1|GPIO_OSPEEDER_OSPEEDR13_0|GPIO_OSPEEDER_OSPEEDR13_1|
                    GPIO_OSPEEDER_OSPEEDR14_0|GPIO_OSPEEDER_OSPEEDR14_1|GPIO_OSPEEDER_OSPEEDR15_0|
                    GPIO_OSPEEDER_OSPEEDR15_1);
    GPIOE->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk|GPIO_PUPDR_PUPD1_Msk|GPIO_PUPDR_PUPD7_Msk|GPIO_PUPDR_PUPD8_Msk|  
                    GPIO_PUPDR_PUPD9_Msk|GPIO_PUPDR_PUPD10_Msk|GPIO_PUPDR_PUPD11_Msk|GPIO_PUPDR_PUPD12_Msk|  
                    GPIO_PUPDR_PUPD13_Msk|GPIO_PUPDR_PUPD14_Msk|GPIO_PUPDR_PUPD15_Msk);
    GPIOE->PUPDR |= (GPIO_PUPDR_PUPD0_0|GPIO_PUPDR_PUPD1_0|GPIO_PUPDR_PUPD7_0|GPIO_PUPDR_PUPD8_0|  
                    GPIO_PUPDR_PUPD9_0|GPIO_PUPDR_PUPD10_0|GPIO_PUPDR_PUPD11_0|GPIO_PUPDR_PUPD12_0|  
                    GPIO_PUPDR_PUPD13_0|GPIO_PUPDR_PUPD14_0|GPIO_PUPDR_PUPD15_0);
    /* PF0~5/11~15 复用功能输出 */
    GPIOF->MODER &= ~(GPIO_MODER_MODE0_Msk|GPIO_MODER_MODE1_Msk|GPIO_MODER_MODE2_Msk| 
                  GPIO_MODER_MODE3_Msk|GPIO_MODER_MODE4_Msk|GPIO_MODER_MODE5_Msk| 
                  GPIO_MODER_MODE11_Msk|GPIO_MODER_MODE12_Msk|GPIO_MODER_MODE13_Msk| 
                  GPIO_MODER_MODE14_Msk|GPIO_MODER_MODE15_Msk);
    GPIOF->MODER |= (GPIO_MODER_MODE0_1|GPIO_MODER_MODE1_1|GPIO_MODER_MODE2_1| 
                    GPIO_MODER_MODE3_1|GPIO_MODER_MODE4_1|GPIO_MODER_MODE5_1| 
                    GPIO_MODER_MODE11_1|GPIO_MODER_MODE12_1|GPIO_MODER_MODE13_1| 
                    GPIO_MODER_MODE14_1|GPIO_MODER_MODE15_1);
    GPIOF->OTYPER &= ~(GPIO_OTYPER_OT0_Msk|GPIO_OTYPER_OT1_Msk|GPIO_OTYPER_OT2_Msk| 
                    GPIO_OTYPER_OT3_Msk|GPIO_OTYPER_OT4_Msk|GPIO_OTYPER_OT5_Msk| 
                    GPIO_OTYPER_OT11_Msk|GPIO_OTYPER_OT12_Msk|GPIO_OTYPER_OT13_Msk| 
                    GPIO_OTYPER_OT14_Msk|GPIO_OTYPER_OT15_Msk);
    GPIOF->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0_Msk|GPIO_OSPEEDR_OSPEED1_Msk|GPIO_OSPEEDR_OSPEED2_Msk| 
                        GPIO_OSPEEDR_OSPEED3_Msk|GPIO_OSPEEDR_OSPEED4_Msk|GPIO_OSPEEDR_OSPEED5_Msk| 
                        GPIO_OSPEEDR_OSPEED11_Msk|GPIO_OSPEEDR_OSPEED12_Msk|GPIO_OSPEEDR_OSPEED13_Msk| 
                        GPIO_OSPEEDR_OSPEED14_Msk|GPIO_OSPEEDR_OSPEED15_Msk);
    GPIOF->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0_0|GPIO_OSPEEDER_OSPEEDR0_1|GPIO_OSPEEDER_OSPEEDR1_0|
                    GPIO_OSPEEDER_OSPEEDR1_1|GPIO_OSPEEDER_OSPEEDR2_0|GPIO_OSPEEDER_OSPEEDR2_1|
                    GPIO_OSPEEDER_OSPEEDR3_0|GPIO_OSPEEDER_OSPEEDR3_1|GPIO_OSPEEDER_OSPEEDR4_0|
                    GPIO_OSPEEDER_OSPEEDR4_1|GPIO_OSPEEDER_OSPEEDR5_0|GPIO_OSPEEDER_OSPEEDR5_1|
                    GPIO_OSPEEDER_OSPEEDR11_0|GPIO_OSPEEDER_OSPEEDR11_1|GPIO_OSPEEDER_OSPEEDR12_0|
                    GPIO_OSPEEDER_OSPEEDR12_1|GPIO_OSPEEDER_OSPEEDR13_0|GPIO_OSPEEDER_OSPEEDR13_1|
                    GPIO_OSPEEDER_OSPEEDR14_0|GPIO_OSPEEDER_OSPEEDR14_1|GPIO_OSPEEDER_OSPEEDR15_0|
                    GPIO_OSPEEDER_OSPEEDR15_1);
    GPIOF->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk|GPIO_PUPDR_PUPD1_Msk|GPIO_PUPDR_PUPD2_Msk| 
                    GPIO_PUPDR_PUPD3_Msk|GPIO_PUPDR_PUPD4_Msk|GPIO_PUPDR_PUPD5_Msk| 
                    GPIO_PUPDR_PUPD11_Msk|GPIO_PUPDR_PUPD12_Msk|GPIO_PUPDR_PUPD13_Msk| 
                    GPIO_PUPDR_PUPD14_Msk|GPIO_PUPDR_PUPD15_Msk);
    GPIOF->PUPDR |= (GPIO_PUPDR_PUPD0_0|GPIO_PUPDR_PUPD1_0|GPIO_PUPDR_PUPD2_0| 
                    GPIO_PUPDR_PUPD3_0|GPIO_PUPDR_PUPD4_0|GPIO_PUPDR_PUPD5_0| 
                    GPIO_PUPDR_PUPD11_0|GPIO_PUPDR_PUPD12_0|GPIO_PUPDR_PUPD13_0| 
                    GPIO_PUPDR_PUPD14_0|GPIO_PUPDR_PUPD15_0);
    /* PG0~2/4/5/8/15 复用功能输出 */ 
    GPIOG->MODER &= ~(GPIO_MODER_MODE0_Msk|GPIO_MODER_MODE1_Msk|GPIO_MODER_MODE2_Msk|
                  GPIO_MODER_MODE4_Msk|GPIO_MODER_MODE5_Msk|GPIO_MODER_MODE8_Msk|
                  GPIO_MODER_MODE15_Msk);
    GPIOG->MODER |= (GPIO_MODER_MODE0_1|GPIO_MODER_MODE1_1|GPIO_MODER_MODE2_1|
                    GPIO_MODER_MODE4_1|GPIO_MODER_MODE5_1|GPIO_MODER_MODE8_1|
                    GPIO_MODER_MODE15_1);
    GPIOG->OTYPER &= ~(GPIO_OTYPER_OT0_Msk|GPIO_OTYPER_OT1_Msk|GPIO_OTYPER_OT2_Msk|
                    GPIO_OTYPER_OT4_Msk|GPIO_OTYPER_OT5_Msk|GPIO_OTYPER_OT8_Msk|
                    GPIO_OTYPER_OT15_Msk);
    GPIOG->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0_Msk|GPIO_OSPEEDR_OSPEED1_Msk|GPIO_OSPEEDR_OSPEED2_Msk|
                        GPIO_OSPEEDR_OSPEED4_Msk|GPIO_OSPEEDR_OSPEED5_Msk|GPIO_OSPEEDR_OSPEED8_Msk|
                        GPIO_OSPEEDR_OSPEED15_Msk);
    GPIOG->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0_0|GPIO_OSPEEDER_OSPEEDR0_1|GPIO_OSPEEDER_OSPEEDR1_0|
                    GPIO_OSPEEDER_OSPEEDR1_1|GPIO_OSPEEDER_OSPEEDR2_0|GPIO_OSPEEDER_OSPEEDR2_1|
                    GPIO_OSPEEDER_OSPEEDR4_0|GPIO_OSPEEDER_OSPEEDR4_1|GPIO_OSPEEDER_OSPEEDR5_0|
                    GPIO_OSPEEDER_OSPEEDR5_1|GPIO_OSPEEDER_OSPEEDR8_0|GPIO_OSPEEDER_OSPEEDR8_1|
                    GPIO_OSPEEDER_OSPEEDR15_0|GPIO_OSPEEDER_OSPEEDR15_1);
    GPIOG->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk|GPIO_PUPDR_PUPD1_Msk|GPIO_PUPDR_PUPD2_Msk|
                    GPIO_PUPDR_PUPD4_Msk|GPIO_PUPDR_PUPD5_Msk|GPIO_PUPDR_PUPD8_Msk|
                    GPIO_PUPDR_PUPD15_Msk);
    GPIOG->PUPDR |= (GPIO_PUPDR_PUPD0_0|GPIO_PUPDR_PUPD1_0|GPIO_PUPDR_PUPD2_0|
                    GPIO_PUPDR_PUPD4_0|GPIO_PUPDR_PUPD5_0|GPIO_PUPDR_PUPD8_0|
                    GPIO_PUPDR_PUPD15_0);
    /* PC0,2,3              AF12 */
    GPIOC->AFR[0] &= ~(GPIO_AFRL_AFRL0|GPIO_AFRL_AFRL2|GPIO_AFRL_AFRL3);
    GPIOC->AFR[0] |= (GPIO_AFRL_AFRL0_2|GPIO_AFRL_AFRL0_3|GPIO_AFRL_AFRL2_2|GPIO_AFRL_AFRL2_3|  
                    GPIO_AFRL_AFRL3_2|GPIO_AFRL_AFRL3_3);
    /* PD0/1/8/9/10/14/15   AF12 */
    GPIOD->AFR[0] &= ~(GPIO_AFRL_AFRL0|GPIO_AFRL_AFRL1);
    GPIOD->AFR[0] |= (GPIO_AFRL_AFRL0_2|GPIO_AFRL_AFRL0_3|GPIO_AFRL_AFRL1_2|GPIO_AFRL_AFRL1_3);
    GPIOD->AFR[1] &= ~(GPIO_AFRH_AFRH0|GPIO_AFRH_AFRH1|GPIO_AFRH_AFRH2|GPIO_AFRH_AFRH6|GPIO_AFRH_AFRH7);
    GPIOD->AFR[1] |= (GPIO_AFRH_AFRH0_2|GPIO_AFRH_AFRH0_3|GPIO_AFRH_AFRH1_2|GPIO_AFRH_AFRH1_3|  
                    GPIO_AFRH_AFRH2_2|GPIO_AFRH_AFRH2_3|GPIO_AFRH_AFRH6_2|GPIO_AFRH_AFRH6_3| 
                    GPIO_AFRH_AFRH7_2|GPIO_AFRH_AFRH7_3);
    /* PE0/1/7~15           AF12 */
    GPIOE->AFR[0] &= ~(GPIO_AFRL_AFRL0|GPIO_AFRL_AFRL1|GPIO_AFRL_AFRL7);
    GPIOE->AFR[0] |= (GPIO_AFRL_AFRL0_2|GPIO_AFRL_AFRL0_3|GPIO_AFRL_AFRL1_2|GPIO_AFRL_AFRL1_3|  
                    GPIO_AFRL_AFRL7_2|GPIO_AFRL_AFRL7_3);
    GPIOE->AFR[1] &= ~(GPIO_AFRH_AFRH0|GPIO_AFRH_AFRH1|GPIO_AFRH_AFRH2|GPIO_AFRH_AFRH3|GPIO_AFRH_AFRH4|  
                    GPIO_AFRH_AFRH5|GPIO_AFRH_AFRH6|GPIO_AFRH_AFRH7);
    GPIOE->AFR[1] |= (GPIO_AFRH_AFRH0_2|GPIO_AFRH_AFRH0_3|GPIO_AFRH_AFRH1_2|GPIO_AFRH_AFRH1_3|  
                    GPIO_AFRH_AFRH2_2|GPIO_AFRH_AFRH2_3|GPIO_AFRH_AFRH3_2|GPIO_AFRH_AFRH3_3|   
                    GPIO_AFRH_AFRH4_2|GPIO_AFRH_AFRH4_3|GPIO_AFRH_AFRH5_2|GPIO_AFRH_AFRH5_3|  
                    GPIO_AFRH_AFRH6_2|GPIO_AFRH_AFRH6_3|GPIO_AFRH_AFRH7_2|GPIO_AFRH_AFRH7_3);
    /* PF0~5/11~15          AF12 */
    GPIOF->AFR[0] &= ~(GPIO_AFRL_AFRL0|GPIO_AFRL_AFRL1|GPIO_AFRL_AFRL2|GPIO_AFRL_AFRL3|GPIO_AFRL_AFRL4|  
                    GPIO_AFRL_AFRL5);
    GPIOF->AFR[0] |= (GPIO_AFRL_AFRL0_2|GPIO_AFRL_AFRL0_3|GPIO_AFRL_AFRL1_2|GPIO_AFRL_AFRL1_3|  
                    GPIO_AFRL_AFRL2_2|GPIO_AFRL_AFRL2_3|GPIO_AFRL_AFRL3_2|GPIO_AFRL_AFRL3_3|   
                    GPIO_AFRL_AFRL4_2|GPIO_AFRL_AFRL4_3|GPIO_AFRL_AFRL5_2|GPIO_AFRL_AFRL5_3);
    GPIOF->AFR[1] &= ~(GPIO_AFRH_AFRH3|GPIO_AFRH_AFRH4|GPIO_AFRH_AFRH5|GPIO_AFRH_AFRH6|GPIO_AFRH_AFRH7);
    GPIOF->AFR[1] |= (GPIO_AFRH_AFRH3_2|GPIO_AFRH_AFRH3_3|GPIO_AFRH_AFRH4_2|GPIO_AFRH_AFRH4_3|  
                    GPIO_AFRH_AFRH5_2|GPIO_AFRH_AFRH5_3|GPIO_AFRH_AFRH6_2|GPIO_AFRH_AFRH6_3 |  
                    GPIO_AFRH_AFRH7_2|GPIO_AFRH_AFRH7_3);
    /* PG0~2/4/5/8/15       AF12 */
    GPIOG->AFR[0] &= ~(GPIO_AFRL_AFRL2|GPIO_AFRL_AFRL4|GPIO_AFRL_AFRL5);
    GPIOG->AFR[0] |= (GPIO_AFRL_AFRL2_2|GPIO_AFRL_AFRL2_3|GPIO_AFRL_AFRL4_2|GPIO_AFRL_AFRL4_3|   
                    GPIO_AFRL_AFRL5_2|GPIO_AFRL_AFRL5_3);
    GPIOG->AFR[1] &= ~(GPIO_AFRH_AFRH0|GPIO_AFRH_AFRH7);
    GPIOG->AFR[1] |= (GPIO_AFRH_AFRH0_2|GPIO_AFRH_AFRH0_3|GPIO_AFRH_AFRH7_2|GPIO_AFRH_AFRH7_3);

    sdctrlreg |= 1 << 0;                /* 9位列地址 */
    sdctrlreg |= 2 << 2;                /* 13位行地址 */
    sdctrlreg |= 1 << 4;                /* 16位数据位宽 */
    sdctrlreg |= 1 << 6;                /* 4个内部存区(4 BANKS) */
    sdctrlreg |= 2 << 7;                /* 2个CAS延迟 */
    sdctrlreg |= 0 << 9;                /* 允许写访问 */
    sdctrlreg |= 2 << 10;               /* SDRAM时钟=HCLK/2=168M/2=84M=11.9ns */
    sdctrlreg |= 1 << 12;               /* 使能突发访问 */
    sdctrlreg |= 0 << 13;               /* 读通道延迟0个HCLK */
    FMC_Bank5_6->SDCR[0] = sdctrlreg;   /* 设置FMC BANK5 SDRAM控制寄存器(BANK5和6用于管理SDRAM) */

    sdtimereg |= 1 << 0;                /* 加载模式寄存器到激活时间的延迟为2个时钟周期 */
    sdtimereg |= 6 << 4;                /* 退出自刷新延迟为7个时钟周期 */
    sdtimereg |= 5 << 8;                /* 自刷新时间为6个时钟周期 */
    sdtimereg |= 5 << 12;               /* 行循环延迟为6个时钟周期 */
    sdtimereg |= 1 << 16;               /* 恢复延迟为2个时钟周期 */
    sdtimereg |= 1 << 20;               /* 行预充电延迟为2个时钟周期 */
    sdtimereg |= 1 << 24;               /* 行到列延迟为2个时钟周期 */
    FMC_Bank5_6->SDTR[0] = sdtimereg;   /* 设置FMC BANK5 SDRAM时序寄存器 */

    sdram_send_cmd(0, 1, 0, 0);         /* 时钟配置使能 */
    delay_us(500);                      /* 至少延迟500us. */
    sdram_send_cmd(0, 2, 0, 0);         /* 对所有存储区预充电 */
    sdram_send_cmd(0, 3, 8, 0);         /* 设置自刷新次数 */
    mregval |= 1 << 0;                  /* 设置突发长度:1(可以是1/2/4/8) */
    mregval |= 0 << 3;                  /* 设置突发类型:连续(可以是连续/交错) */
    mregval |= 2 << 4;                  /* 设置CAS值:2(可以是2/3) */
    mregval |= 0 << 7;                  /* 设置操作模式:0,标准模式 */
    mregval |= 1 << 9;                  /* 设置突发写模式:1,单点访问 */
    sdram_send_cmd(0, 4, 0, mregval);   /* 设置SDRAM的模式寄存器 */

    /**
     * 刷新频率计数器(以SDCLK频率计数),计算方法:
     * COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
     * 我们使用的SDRAM刷新周期为 64ms,SDCLK=168/2=84Mhz,行数为8192(2^13).
     * 所以,COUNT=64*1000*84/8192-20=636.25
     */
    FMC_Bank5_6->SDRTR = 637 << 1;      /* 设置刷新频率计数器 */
}

/**
 * @brief       在指定地址(addr + Bank5_SDRAM_ADDR)开始,连续写入n个字节
 * @param       pbuf   : 字节指针
 * @param       addr   : 要写入的地址
 * @param       n      : 要写入的字节数
 * @retval      无
*/
void fmc_sdram_write_buffer(uint8_t *pbuf, uint32_t addr, uint32_t n)
{
    for (; n != 0; n--)
    {
        *(volatile uint8_t *)(BANK5_SDRAM_ADDR + addr) = *pbuf;
        addr++;
        pbuf++;
    }
}

/**
 * @brief       在指定地址(addr + Bank5_SDRAM_ADDR)开始,连续读取n个字节
 * @param       pbuf    : 字节指针
 * @param       addr    : 要读取的地址
 * @param       n       : 要读取的字节数
 * @retval      无
*/
void fmc_sdram_read_buffer(uint8_t *pbuf, uint32_t addr, uint32_t n)
{
    for (; n != 0; n--)
    {
        *pbuf++ = *(volatile uint8_t *)(BANK5_SDRAM_ADDR + addr);
        addr++;
    }
}
